// Copyright 2003 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Dan Egnor (egnor@google.com)
//
// A "smart" pointer type with reference tracking.  Every pointer to a
// particular object is kept on a circular linked list.  When the last pointer
// to an object is destroyed or reassigned, the object is deleted.
//
// Used properly, this deletes the object when the last reference goes away.
// There are several caveats:
// - Like all reference counting schemes, cycles lead to leaks.
// - Each smart pointer is actually two pointers (8 bytes instead of 4).
// - Every time a pointer is assigned, the entire list of pointers to that
//   object is traversed.  This class is therefore NOT SUITABLE when there
//   will often be more than two or three pointers to a particular object.
// - References are only tracked as long as linked_ptr<> objects are copied.
//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
//   will happen (double deletion).
//
// A good use of this class is storing object references in STL containers.
// You can safely put linked_ptr<> in a vector<>.
// Other uses may not be as good.
//
// Note: If you use an incomplete type with linked_ptr<>, the class
// *containing* linked_ptr<> must have a constructor and destructor (even
// if they do nothing!).
//
// Bill Gibbons suggested we use something like this.
//
// Thread Safety:
//   Unlike other linked_ptr implementations, in this implementation
//   a linked_ptr object is thread-safe in the sense that:
//     - it's safe to copy linked_ptr objects concurrently,
//     - it's safe to copy *from* a linked_ptr and read its underlying
//       raw pointer (e.g. via get()) concurrently, and
//     - it's safe to write to two linked_ptrs that point to the same
//       shared object concurrently.
// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
// confusion with normal linked_ptr.

#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_

#include <stdlib.h>
#include <assert.h>

#include "gtest/internal/gtest-port.h"

namespace testing
{
    namespace internal
    {

        // Protects copying of all linked_ptr objects.
        GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);

        // This is used internally by all instances of linked_ptr<>.  It needs to be
        // a non-template class because different types of linked_ptr<> can refer to
        // the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
        // So, it needs to be possible for different types of linked_ptr to participate
        // in the same circular linked list, so we need a single class type here.
        //
        // DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
        class linked_ptr_internal
        {
        public:
            // Create a new circle that includes only this instance.
            void join_new()
            {
                next_ = this;
            }

            // Many linked_ptr operations may change p.link_ for some linked_ptr
            // variable p in the same circle as this object.  Therefore we need
            // to prevent two such operations from occurring concurrently.
            //
            // Note that different types of linked_ptr objects can coexist in a
            // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
            // linked_ptr<Derived2>).  Therefore we must use a single mutex to
            // protect all linked_ptr objects.  This can create serious
            // contention in production code, but is acceptable in a testing
            // framework.

            // Join an existing circle.
            // L < g_linked_ptr_mutex
            void join(linked_ptr_internal const *ptr)
            {
                MutexLock lock(&g_linked_ptr_mutex);
                linked_ptr_internal const *p = ptr;

                while (p->next_ != ptr)
                {
                    p = p->next_;
                }

                p->next_ = this;
                next_ = ptr;
            }

            // Leave whatever circle we're part of.  Returns true if we were the
            // last member of the circle.  Once this is done, you can join() another.
            // L < g_linked_ptr_mutex
            bool depart()
            {
                MutexLock lock(&g_linked_ptr_mutex);

                if (next_ == this)
                {
                    return true;
                }

                linked_ptr_internal const *p = next_;

                while (p->next_ != this)
                {
                    p = p->next_;
                }

                p->next_ = next_;
                return false;
            }

        private:
            mutable linked_ptr_internal const *next_;
        };

        template <typename T>
        class linked_ptr
        {
        public:
            typedef T element_type;

            // Take over ownership of a raw pointer.  This should happen as soon as
            // possible after the object is created.
            explicit linked_ptr(T *ptr = NULL)
            {
                capture(ptr);
            }
            ~linked_ptr()
            {
                depart();
            }

            // Copy an existing linked_ptr<>, adding ourselves to the list of references.
            template <typename U> linked_ptr(linked_ptr<U> const &ptr)
            {
                copy(&ptr);
            }
            linked_ptr(linked_ptr const &ptr)    // NOLINT
            {
                assert(&ptr != this);
                copy(&ptr);
            }

            // Assignment releases the old value and acquires the new.
            template <typename U> linked_ptr &operator=(linked_ptr<U> const &ptr)
            {
                depart();
                copy(&ptr);
                return *this;
            }

            linked_ptr &operator=(linked_ptr const &ptr)
            {
                if (&ptr != this)
                {
                    depart();
                    copy(&ptr);
                }

                return *this;
            }

            // Smart pointer members.
            void reset(T *ptr = NULL)
            {
                depart();
                capture(ptr);
            }
            T *get() const
            {
                return value_;
            }
            T *operator->() const
            {
                return value_;
            }
            T &operator*() const
            {
                return *value_;
            }

            bool operator==(T *p) const
            {
                return value_ == p;
            }
            bool operator!=(T *p) const
            {
                return value_ != p;
            }
            template <typename U>
            bool operator==(linked_ptr<U> const &ptr) const
            {
                return value_ == ptr.get();
            }
            template <typename U>
            bool operator!=(linked_ptr<U> const &ptr) const
            {
                return value_ != ptr.get();
            }

        private:
            template <typename U>
            friend class linked_ptr;

            T *value_;
            linked_ptr_internal link_;

            void depart()
            {
                if (link_.depart())
                {
                    delete value_;
                }
            }

            void capture(T *ptr)
            {
                value_ = ptr;
                link_.join_new();
            }

            template <typename U> void copy(linked_ptr<U> const *ptr)
            {
                value_ = ptr->get();

                if (value_)
                {
                    link_.join(&ptr->link_);
                }
                else
                {
                    link_.join_new();
                }
            }
        };

        template<typename T> inline
        bool operator==(T *ptr, const linked_ptr<T>& x)
        {
            return ptr == x.get();
        }

        template<typename T> inline
        bool operator!=(T *ptr, const linked_ptr<T>& x)
        {
            return ptr != x.get();
        }

        // A function to convert T* into linked_ptr<T>
        // Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
        // for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
        template <typename T>
        linked_ptr<T> make_linked_ptr(T *ptr)
        {
            return linked_ptr<T>(ptr);
        }

    }  // namespace internal
}  // namespace testing

#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
